/********************************************************************
	Created:	2012/05/26  14:21
	Filename: 	RLib_LdrSup.h
	Author:		Lactoferrin
	Url:	    http://blog.csdn.net/rrrfff
*********************************************************************/
#include "RLib_Detour.h"
#include "native/RLib_Native.h"
//////////////////////////////////////////////////////////////////////////
using namespace System::Runtimes;

#pragma warning(disable:4706 4310)
//#pragma warning(disable:4706 4204 4310 4214 4057 4221 4244 4201 4212 4100 4211)

#ifndef HEAP_CREATE_ENABLE_EXECUTE
#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000
#endif 
#define Abs(x) ((x)<0?-(x):(x))
#define InBound(x,lb,ub) ((size_t)(x)>=(size_t)(lb))&&((size_t)(x)<=(size_t)(ub))


typedef struct _INSTRUCTION_INFO
{
	unsigned char Size, Opcode, PrefixSize, ASize: 1, OSize: 1, Alt: 1;
	signed long Operand;
} INSTRUCTION_INFO,  *PINSTRUCTION_INFO;
typedef enum _RELADDR_TYPE
{
	AbsAddr = 0, Call16, Call32, Jmp8, Jmp16, Jmp32, Jcxz, Jcc8, Jcc16, Jcc32
} RELADDR_TYPE,  *PRELADDR_TYPE;

static void *RedirectHeap = 0;
//-------------------------------------------------------------------------

static char ToBin[][256] = 
{
	"00000000", "00000001", "00000010", "00000011", "00000100", "00000101", "00000110", "00000111", "00001000", "00001001", "00001010", "00001011", "00001100", "00001101", "00001110", "00001111", "00010000", "00010001", "00010010", "00010011", "00010100", "00010101", "00010110", "00010111", "00011000", "00011001", "00011010", "00011011", "00011100", "00011101", "00011110", "00011111", "00100000", "00100001", "00100010", "00100011", "00100100", "00100101", "00100110", "00100111", "00101000", "00101001", "00101010", "00101011", "00101100", "00101101", "00101110", "00101111", "00110000", "00110001", "00110010", "00110011", "00110100", "00110101", "00110110", "00110111", "00111000", "00111001", "00111010", "00111011", "00111100", "00111101", "00111110", "00111111", "01000000", "01000001", "01000010", "01000011", "01000100", "01000101", "01000110", "01000111", "01001000", "01001001", "01001010", "01001011", "01001100", "01001101", "01001110", "01001111", "01010000", "01010001", "01010010", "01010011", "01010100", "01010101", "01010110", "01010111", "01011000", "01011001", "01011010", "01011011", "01011100", "01011101", "01011110", "01011111", "01100000", "01100001", "01100010", "01100011", "01100100", "01100101", "01100110", "01100111", "01101000", "01101001", "01101010", "01101011", "01101100", "01101101", "01101110", "01101111", "01110000", "01110001", "01110010", "01110011", "01110100", "01110101", "01110110", "01110111", "01111000", "01111001", "01111010", "01111011", "01111100", "01111101", "01111110", "01111111", "10000000", "10000001", "10000010", "10000011", "10000100", "10000101", "10000110", "10000111", "10001000", "10001001", "10001010", "10001011", "10001100", "10001101", "10001110", "10001111", "10010000", "10010001", "10010010", "10010011", "10010100", "10010101", "10010110", "10010111", "10011000", "10011001", "10011010", "10011011", "10011100", "10011101", "10011110", "10011111", "10100000", "10100001", "10100010", "10100011", "10100100", "10100101", "10100110", "10100111", "10101000", "10101001", "10101010", "10101011", "10101100", "10101101", "10101110", "10101111", "10110000", "10110001", "10110010", "10110011", "10110100", "10110101", "10110110", "10110111", "10111000", "10111001", "10111010", "10111011", "10111100", "10111101", "10111110", "10111111", "11000000", "11000001", "11000010", "11000011", "11000100", "11000101", "11000110", "11000111", "11001000", "11001001", "11001010", "11001011", "11001100", "11001101", "11001110", "11001111", "11010000", "11010001", "11010010", "11010011", "11010100", "11010101", "11010110", "11010111", "11011000", "11011001", "11011010", "11011011", "11011100", "11011101", "11011110", "11011111", "11100000", "11100001", "11100010", "11100011", "11100100", "11100101", "11100110", "11100111", "11101000", "11101001", "11101010", "11101011", "11101100", "11101101", "11101110", "11101111", "11110000", "11110001", "11110010", "11110011", "11110100", "11110101", "11110110", "11110111", "11111000", "11111001", "11111010", "11111011", "11111100", "11111101", "11111110", "11111111"
};

static char InstructionFormat[] = "0011 0111\n""1101 0101 : 0000 1010\n""1101 0100 : 0000 1010\n""0011 1111\n""0001 000w : 11 reg1 reg2\n""0001 001w : 11 reg1 reg2\n""0001 001w : mod reg r/m\n""0001 000w : mod reg r/m\n""1000 00sw : 11 010 reg : immediate data\n""0001 010w : immediate data\n""1000 00sw : mod 010 r/m : immediate data\n""0000 000w : 11 reg1 reg2\n""0000 001w : 11 reg1 reg2 \n""0000 001w : mod reg r/m\n""0000 000w : mod reg r/m\n""1000 00sw : 11 000 reg : immediate data\n""0000 010w : immediate data\n""1000 00sw : mod 000 r/m : immediate data\n""0010 000w : 11 reg1 reg2\n""0010 001w : 11 reg1 reg2 \n""0010 001w : mod reg r/m\n""0010 000w : mod reg r/m\n""0010 010w : immediate data\n""1000 00sw : mod 100 r/m : immediate data\n""0110 0011 : 11 reg1 reg2\n""0110 0011 : mod reg r/m\n""0110 0010 : mod reg r/m\n""0000 1111 : 1011 1100 : 11 reg2 reg1\n""0000 1111 : 1011 1100 : mod reg r/m\n""0000 1111 : 1011 1101 : 11 reg2 reg1\n""0000 1111 : 1011 1101 : mod reg r/m\n""0000 1111 : 1100 1 reg\n""0000 1111 : 1011 1010 : 11 100 reg: imm8 data\n""0000 1111 : 1011 1010 : mod 100 r/m : imm8 data\n""0000 1111 : 1010 0011 : 11 reg2 reg1\n""0000 1111 : 1010 0011 : mod reg r/m\n""0000 1111 : 1011 1010 : 11 111 reg: imm8 data\n""0000 1111 : 1011 1010 : mod 111 r/m : imm8 data\n""0000 1111 : 1011 1011 : 11 reg2 reg1\n""0000 1111 : 1011 1011 : mod reg r/m\n""0000 1111 : 1011 1010 : 11 110 reg: imm8 data\n""0000 1111 : 1011 1010 : mod 110 r/m : imm8 data\n""0000 1111 : 1011 0011 : 11 reg2 reg1\n""0000 1111 : 1011 0011 : mod reg r/m\n""0000 1111 : 1011 1010 : 11 101 reg: imm8 data\n""0000 1111 : 1011 1010 : mod 101 r/m : imm8 data\n""0000 1111 : 1010 1011 : 11 reg2 reg1\n""0000 1111 : 1010 1011 : mod reg r/m\n""1110 1000 : full displacement\n""1111 1111 : 11 010 reg\n""1111 1111 : mod 010 r/m\n""1001 1010 : unsigned full offset, selector\n""1111 1111 : mod 011 r/m\n""1001 1000\n""1001 1001\n""1111 1000\n""1111 1100\n""1111 1010\n""0000 1111 : 0000 0110\n""1111 0101\n""0000 1111 : 0100 tttn : 11 reg1 reg2\n""0000 1111 : 0100 tttn : mod mem r/m\n""0011 100w : 11 reg1 reg2\n""0011 101w : 11 reg1 reg2\n""0011 100w : mod reg r/m\n""0011 101w : mod reg r/m\n""1000 00sw : 11 111 reg : immediate data\n""0011 110w : immediate data\n""1000 00sw : mod 111 r/m : immediate data\n""1010 011w\n""0000 1111 : 1011 000w : 11 reg2 reg1\n""0000 1111 : 1011 000w : mod reg r/m\n""0000 1111 : 1100 0111 : mod reg r/m\n""0000 1111 : 1010 0010\n""1001 1001\n""1001 1000\n""0010 0111\n""0010 1111\n""1111 111w : 11 001 reg\n""0100 1 reg\n""1111 111w : mod 001 r/m\n""1111 011w : 11 110 reg\n""1111 011w : mod 110 r/m\n""1100 1000 : 16-bit displacement : 8-bit level (L)\n""1111 0100\n""1111 011w : 11 111 reg\n""1111 011w : mod 111 r/m\n""1111 011w : 11 101 reg\n""1111 011w : mod 101 reg\n""0000 1111 : 1010 1111 : 11 : reg1 reg2\n""0000 1111 : 1010 1111 : mod reg r/m\n""0110 10s1 : 11 reg1 reg2 : immediate data\n""0110 10s1 : mod reg r/m : immediate data\n""1110 010w : port number\n""1110 110w\n""1111 111w : 11 000 reg\n""0100 0 reg\n""1111 111w : mod 000 r/m\n""0110 110w\n""1100 1101 : type\n""1100 1100\n""1100 1110\n""0000 1111 : 0000 1000\n""0000 1111 : 0000 0001 : mod 111 r/m\n""1100 1111\n""0111 tttn : 8-bit displacement\n""0000 1111 : 1000 tttn : full displacement\n""1110 0011 : 8-bit displacement\n""1110 1011 : 8-bit displacement\n""1110 1001 : full displacement\n""1111 1111 : 11 100 reg\n""1111 1111 : mod 100 r/m\n""1110 1010 : unsigned full offset, selector\n""1111 1111 : mod 101 r/m\n""1001 1111\n""0000 1111 : 0000 0010 : 11 reg1 reg2\n""0000 1111 : 0000 0010 : mod reg r/m\n""1100 0101 : mod reg r/m\n""1000 1101 : mod reg r/m\n""1100 1001\n""1100 0100 : mod reg r/m\n""0000 1111 : 1011 0100 : mod reg r/m\n""0000 1111 : 0000 0001 : mod 010 r/m\n""0000 1111 : 1011 0101 : mod reg r/m\n""0000 1111 : 0000 0000 : 11 010 reg\n""0000 1111 : 0000 0000 : mod 010 r/m\n""0000 1111 : 0000 0001 : 11 110 reg\n""0000 1111 : 0000 0001 : mod 110 r/m\n""1111 0000\n""1010 110w\n""1110 0010 : 8-bit displacement\n""1110 0001 : 8-bit displacement\n""1110 0000 : 8-bit displacement\n""0000 1111 : 0000 0011 : 11 reg1 reg2\n""0000 1111 : 0000 0011 : mod reg r/m\n""0000 1111 : 1011 0010 : mod reg r/m\n""0000 1111 : 0000 0000 : 11 011 reg\n""0000 1111 : 0000 0000 : mod 011 r/m\n""1000 100w : 11 reg1 reg2\n""1000 101w : 11 reg1 reg2\n""1000 101w : mod reg r/m\n""1000 100w : mod reg r/m\n""1100 011w : 11 000 reg : immediate data\n""1011 w reg : immediate data\n""1100 011w : mod 000 r/m : immediate data\n""1010 000w : full displacement\n""1010 001w : full displacement\n""0000 1111 : 0010 0010 : 11 000 reg\n""0000 1111 : 0010 0010 : 11 010reg\n""0000 1111 : 0010 0010 : 11 011 reg\n""0000 1111 : 0010 0010 : 11 100 reg\n""0000 1111 : 0010 0000 : 11 eee reg\n""0000 1111 : 0010 0011 : 11 eee reg\n""0000 1111 : 0010 0011 : 11 eee reg\n""0000 1111 : 0010 0011 : 11 eee reg\n""0000 1111 : 0010 0001 : 11 eee reg\n""0000 1111 : 0010 0001 : 11 eee reg\n""0000 1111 : 0010 0001 : 11 eee reg\n""1000 1110 : 11 sreg3 reg\n""1000 1110 : 11 sreg3 reg\n""1000 1110 : mod sreg3 r/m\n""1000 1110 : mod sreg3 r/m\n""1000 1100 : 11 sreg3 reg\n""1000 1100 : mod sreg3 r/m\n""1010 010w\n""0000 1111 : 1011 111w : 11 reg1 reg2\n""0000 1111 : 1011 111w : mod reg r/m\n""0000 1111 : 1011 011w : 11 reg1 reg2\n""0000 1111 : 1011 011w : mod reg r/m\n""1111 011w : 11 100 reg\n""1111 011w : mod 100 reg\n""1111 011w : 11 011 reg\n""1111 011w : mod 011 r/m\n""1001 0000\n""1111 011w : 11 010 reg\n""1111 011w : mod 010 r/m\n""0000 100w : 11 reg1 reg2\n""0000 101w : 11 reg1 reg2 \n""0000 101w : mod reg r/m\n""0000 100w : mod reg r/m\n""1000 00sw : 11 001 reg : immediate data\n""0000 110w : immediate data\n""1000 00sw : mod 001 r/m : immediate data\n""1110 011w : port number\n""1110 111w\n""0110 111w\n""1000 1111 : 11 000 reg\n""0101 1 reg\n""1000 1111 : mod 000 r/m\n""000 sreg2 111\n""000 sreg2 111\n""0000 1111: 10 sreg3 001\n""0110 0001\n""1001 1101\n""1111 1111 : 11 110 reg\n""0101 0 reg\n""1111 1111 : mod 110 r/m\n""0110 10s0 : immediate data\n""000 sreg2 110\n""0000 1111: 10 sreg3 000\n""0110 0000\n""1001 1100\n""1101 000w : 11 010 reg\n""1101 000w : mod 010 r/m\n""1101 001w : 11 010 reg\n""1101 001w : mod 010 r/m\n""1100 000w : 11 010 reg : imm8 data\n""1100 000w : mod 010 r/m : imm8 data\n""1101 000w : 11 011 reg\n""1101 000w : mod 011 r/m\n""1101 001w : 11 011 reg\n""1101 001w : mod 011 r/m\n""1100 000w : 11 011 reg : imm8 data\n""1100 000w : mod 011 r/m : imm8 data\n""0000 1111 : 0011 0010\n""0000 1111 : 0011 0011\n""0000 1111 : 0011 0001\n""1111 0011 : 0110 110w\n""1111 0011 : 1010 110w\n""1111 0011 : 1010 010w\n""1111 0011 : 0110 111w\n""1111 0011 : 1010 101w\n""1111 0011 : 1010 011w\n""1111 0011 : 1010 111w\n""1111 0010 : 1010 011w\n""1111 0010 : 1010 111w\n""1100 0011\n""1100 0010 : 16-bit displacement\n""1100 1011\n""1100 1010 : 16-bit displacement\n""1101 000w : 11 000 reg\n""1101 000w : mod 000 r/m\n""1101 001w : 11 000 reg\n""1101 001w : mod 000 r/m\n""1100 000w : 11 000 reg : imm8 data\n""1100 000w : mod 000 r/m : imm8 data\n""1101 000w : 11 001 reg\n""1101 000w : mod 001 r/m\n""1101 001w : 11 001 reg\n""1101 001w : mod 001 r/m\n""1100 000w : 11 001 reg : imm8 data\n""1100 000w : mod 001 r/m : imm8 data\n""0000 1111 : 1010 1010\n""1001 1110\n""1101 000w : 11 111 reg\n""1101 000w : mod 111 r/m\n""1101 001w : 11 111 reg\n""1101 001w : mod 111 r/m\n""1100 000w : 11 111 reg : imm8 data\n""1100 000w : mod 111 r/m : imm8 data\n""0001 100w : 11 reg1 reg2\n""0001 101w : 11 reg1 reg2 \n""0001 101w : mod reg r/m\n""0001 100w : mod reg r/m\n""1000 00sw : 11 011 reg : immediate data\n""0001 110w : immediate data\n""1000 00sw : mod 011 r/m : immediate data\n""1101 111w\n""0000 1111 : 1001 tttn : 11 000 reg\n""0000 1111 : 1001 tttn : mod 000 r/m\n""0000 1111 : 0000 0001 : mod 000 r/m\n""1101 000w : 11 100 reg\n""1101 000w : mod 100 r/m\n""1101 001w : 11 100 reg\n""1101 001w : mod 100 r/m\n""1100 000w : 11 100 reg : imm8 data\n""1100 000w : mod 100 r/m : imm8 data\n""0000 1111 : 1010 0100 : 11 reg2 reg1 : imm8\n""0000 1111 : 1010 0100 : mod reg r/m : imm8\n""0000 1111 : 1010 0101 : 11 reg2 reg1\n""0000 1111 : 1010 0101 : mod reg r/m\n""1101 000w : 11 101 reg\n""1101 000w : mod 101 r/m\n""1101 001w : 11 101 reg\n""1101 001w : mod 101 r/m\n""1100 000w : 11 101 reg : imm8 data\n""1100 000w : mod 101 r/m : imm8 data\n""0000 1111 : 1010 1100 : 11 reg2 reg1 : imm8\n""0000 1111 : 1010 1100 : mod reg r/m : imm8\n""0000 1111 : 1010 1101 : 11 reg2 reg1\n""0000 1111 : 1010 1101 : mod reg r/m\n""0000 1111 : 0000 0001 : mod 001 r/m\n""0000 1111 : 0000 0000 : 11 000 reg\n""0000 1111 : 0000 0000 : mod 000 r/m\n""0000 1111 : 0000 0001 : 11 100 reg\n""0000 1111 : 0000 0001 : mod 100 r/m\n""1111 1001\n""1111 1101\n""1111 1011\n""1010 101w\n""0000 1111 : 0000 0000 : 11 001 reg\n""0000 1111 : 0000 0000 : mod 001 r/m\n""0010 100w : 11 reg1 reg2\n""0010 101w : 11 reg1 reg2 \n""0010 101w : mod reg r/m\n""0010 100w : mod reg r/m\n""1000 00sw : 11 101 reg : immediate data\n""0010 110w : immediate data\n""1000 00sw : mod 101 r/m : immediate data\n""1000 010w : 11 reg1 reg2\n""1000 010w : mod reg r/m\n""1111 011w : 11 000 reg : immediate data\n""1010 100w : immediate data\n""1111 011w : mod 000 r/m : immediate data\n""0000 FFFF : 0000 1011\n""0000 1111 : 0000 0000 : 11 100 reg\n""0000 1111 : 0000 0000 : mod 100 r/m\n""0000 1111 : 0000 0000 : 11 101 reg\n""0000 1111 : 0000 0000 : mod 101 r/m\n""1001 1011\n""0000 1111 : 0000 1001\n""0000 1111 : 0011 0000\n""0000 1111 : 1100 000w : 11 reg2 reg1\n""0000 1111 : 1100 000w : mod reg r/m\n""1000 011w : 11 reg1 reg2\n""1001 0 reg\n""1000 011w : mod reg r/m\n""1101 0111\n""0011 000w : 11 reg1 reg2\n""0011 001w : 11 reg1 reg2 \n""0011 001w : mod reg r/m\n""0011 000w : mod reg r/m\n""1000 00sw : 11 110 reg : immediate data\n""0011 010w : immediate data\n""1000 00sw : mod 110 r/m : immediate data\n""0000 1111:01110111 \n""0000 1111:01101110: 11 mmxreg reg\n""0000 1111:01111110: 11 mmxreg reg\n""0000 1111:01101110: mod mmxreg r/m\n""0000 1111:01111110: mod mmxreg r/m\n""0000 1111:01101111: 11 mmxreg1 mmxreg2\n""0000 1111:01111111: 11 mmxreg1 mmxreg2\n""0000 1111:01101111: mod mmxreg r/m\n""0000 1111:01111111: mod mmxreg r /m\n""0000 1111:01101011: 11 mmxreg1 mmxreg2\n""0000 1111:01101011: mod mmxreg r/m\n""0000 1111:01100011: 11 mmxreg1 mmxreg2\n""0000 1111:01100011: mod mmxreg r/m\n""0000 1111:01100111: 11 mmxreg1 mmxreg2\n""0000 1111:01100111: mod mmxreg r/m\n""0000 1111:111111gg: 11 mmxreg1 mmxreg2\n""0000 1111:111111gg: mod mmxreg r/m\n""0000 1111:111011gg: 11 mmxreg1 mmxreg2\n""0000 1111:111011gg: mod mmxreg r/m\n""0000 1111:110111gg: 11 mmxreg1 mmxreg2\n""0000 1111:110111gg: mod mmxreg r/m\n""0000 1111:11011011: 11 mmxreg1 mmxreg2\n""0000 1111:11011011: mod mmxreg r/m\n""0000 1111:11011111: 11 mmxreg1 mmxreg2\n""0000 1111:11011111: mod mmxreg r/m\n""0000 1111:011101gg: 11 mmxreg1 mmxreg2\n""0000 1111:011101gg: mod mmxreg r/m\n""0000 1111:011001gg: 11 mmxreg1 mmxreg2\n""0000 1111:011001gg: mod mmxreg r/m\n""0000 1111:11110101: 11 mmxreg1 mmxreg2\n""0000 1111:11110101: mod mmxreg r/m\n""0000 1111:11100101: 11 mmxreg1 mmxreg2\n""0000 1111:11100101: mod mmxreg r/m\n""0000 1111:11010101: 11 mmxreg1 mmxreg2\n""0000 1111:11010101: mod mmxreg r/m\n""0000 1111:11101011: 11 mmxreg1 mmxreg2\n""0000 1111:11101011: mod mmxreg r/m\n""0000 1111:111100gg: 11 mmxreg1 mmxreg2\n""0000 1111:111100gg: mod mmxreg r/m\n""0000 1111:011100gg: 11 110 mmxreg: imm8 data\n""0000 1111:111000gg: 11 mmxreg1 mmxreg2\n""0000 1111:111000gg: mod mmxreg r/m\n""0000 1111:011100gg: 11 100 mmxreg: imm8 data\n""0000 1111:110100gg: 11 mmxreg1 mmxreg2\n""0000 1111:110100gg: mod mmxreg r/m\n""0000 1111:011100gg: 11 010 mmxreg: imm8 data\n""0000 1111:111110gg: 11 mmxreg1 mmxreg2\n""0000 1111:111110gg: mod mmxreg r/m\n""0000 1111:111010gg: 11 mmxreg1 mmxreg2\n""0000 1111:111010gg: mod mmxreg r/m\n""0000 1111:110110gg: 11 mmxreg1 mmxreg2\n""0000 1111:110110gg: mod mmxreg r/m\n""0000 1111:011010gg: 11 mmxreg1 mmxreg2\n""0000 1111:011010gg: mod mmxreg r/m\n""0000 1111:011000gg: 11 mmxreg1 mmxreg2\n""0000 1111:011000gg: mod mmxreg r/m\n""0000 1111:11101111: 11 mmxreg1 mmxreg2\n""0000 1111:11101111: mod mmxreg r/m\n""00001111:01011000:11 xmmreg1 xmmreg2 \n""00001111:01011000:  mod xmmreg r/m\n""11110011:00001111:01011000:11 xmmreg1 xmmreg2\n""11110011:00001111:01011000: mod xmmreg r/m\n""00001111:01010101:11 xmmreg1 xmmreg2\n""00001111:01010101:  mod xmmreg r/m\n""00001111:01010100:11 xmmreg1 xmmreg2\n""00001111:01010100:  mod xmmreg r/m\n""00001111:11000010:11 xmmreg1 xmmreg2: imm8 data\n""00001111:11000010:  mod xmmreg r/m: imm8 data\n""11110011:00001111:11000010:11 xmmreg1 xmmreg2: \n""imm8 data\n""11110011:00001111:11000010: mod xmmreg r/m: imm8 \n""data\n""00001111:00101111:11 xmmreg1 xmmreg2\n""00001111:00101111:  mod xmmreg r/m\n""00001111:00101010:11 xmmreg1 mmreg1\n""00001111:00101010:  mod xmmreg r/m\n""00001111:00101101:11 mmreg1 xmmreg1\n""00001111:00101101:  mod mmreg r/m\n""11110011:00001111:00101010:11 xmmreg r32\n""11110011:00001111:00101010: mod xmmreg r/m\n""11110011:00001111:00101101:11 r32 xmmreg\n""11110011:00001111:00101101: mod r32 r/m\n""00001111:00101100:11 mmreg1 xmmreg1\n""00001111:00101100:  mod mmreg r/m\n""11110011:00001111:00101100:11 r32 xmmreg1\n""11110011:00001111:00101100: mod r32 r/m\n""00001111:01011110:11 xmmreg1 xmmreg2\n""00001111:01011110:  mod xmmreg r/m\n""11110011:00001111:01011110:11 xmmreg1 xmmreg2\n""11110011:00001111:01011110: mod xmmreg r/m\n""00001111:10101110:01 m512 \n""00001111:10101110:00 m512 \n""00001111:10101110:10 m32\n""00001111:01011111:11 xmmreg1 xmmreg2\n""00001111:01011111: mod xmmreg r/m\n""11110011:00001111:01011111:11 xmmreg1 xmmreg2\n""11110011:00001111:01011111: mod xmmreg r/m\n""00001111:01011101:11 xmmreg1 xmmreg2\n""00001111:01011101: mod xmmreg r/m\n""11110011:00001111:01011101:11 xmmreg1 xmmreg2\n""11110011:00001111:01011101: mod xmmreg r/m\n""00001111:00101000:11 xmmreg2 xmmreg1\n""00001111:00101000: mod xmmreg r/m\n""00001111:00101001:11 xmmreg1 xmmreg2\n""00001111:00101001: mod xmmreg r/m\n""00001111:00010010:11 xmmreg1 xmmreg2\n""00001111:00010110: mod xmmreg r/m\n""00001111:00010111: mod xmmreg r/m\n""00001111:00010110:11 xmmreg1 xmmreg2\n""00001111:00010010: mod xmmreg r/m \n""00001111:00010011: mod xmmreg r/m\n""00001111:01010000:11 r32 xmmreg\n""11110011:00001111:00010000:11 xmmreg2 xmmreg1\n""11110011:00001111:00010000: mod xmmreg r/m\n""11110011:00001111:00010000:11 xmmreg1 xmmreg2\n""11110011:00001111:00010000: mod xmmreg r/m\n""00001111:00010000:11 xmmreg2 xmmreg1\n""00001111:00010000: mod xmmreg r/m\n""00001111:00010001:11 xmmreg1 xmmreg2\n""00001111:00010001: mod xmmreg r/m\n""00001111:01011001:11 xmmreg1 xmmreg2\n""00001111:01011001: mod xmmreg rm\n""11110011:00001111:010111001:11 xmmreg1 xmmreg2\n""11110011:00001111:010111001: mod xmmreg r/m\n""00001111:01010110:11 xmmreg1 xmmreg2\n""00001111:01010110 mod xmmreg r/m\n""00001111:01010011:11 xmmreg1 xmmreg2\n""00001111:01010011: mod xmmreg r/m\n""11110011:00001111:01010011:11 xmmreg1 xmmreg2\n""11110011:00001111:01010011: mod xmmreg r/m\n""00001111:01010010:11 xmmreg1 xmmreg2\n""00001111:01010010 mode xmmreg r/m\n""11110011:00001111:01010010:11 xmmreg1 xmmreg2\n""11110011:00001111:01010010 mod xmmreg r/m\n""00001111:11000110:11 xmmreg1 xmmreg2: imm8\n""00001111:11000110: mod xmmreg r/m: imm8\n""00001111:01010001:11 xmmreg1 xmmreg 2\n""00001111:01010001 mod xmmreg r/m\n""01010011:00001111:01010001:11 xmmreg1 xmmreg 2\n""01010011:00001111:01010001 mod xmmreg r/m\n""00001111:10101110:11 m32\n""00001111:01011100:11 xmmreg1 xmmreg2\n""00001111:01011100 mod xmmreg r/m\n""11110011:00001111:01011100:11 xmmreg1 xmmreg2\n""11110011:00001111:01011100 mod xmmreg r/m\n""00001111:00101110:11 xmmreg1 xmmreg2\n""00001111:00101110 mod xmmreg r/m\n""00001111:00010101:11 xmmreg1 xmmreg2\n""00001111:00010101 mod xmmreg r/m\n""00001111:00010100:11 xmmreg1 xmmreg2\n""00001111:00010100 mod xmmreg r/m\n""00001111:01010111:11 xmmreg1 xmmreg2\n""00001111:01010111 mod xmmreg r/m\n""00001111:11100000:11 mmreg1 mmreg2\n""00001111:11100011:11 mmreg1 mmreg2\n""00001111:11100000 mod mmreg r/m\n""00001111:11100011 mod mmreg r/m\n""00001111:11000101:11 mmreg r32: imm8\n""00001111:11000100:11 r32 mmreg1: imm8\n""00001111:11000100 mod mmreg r/m: imm8\n""00001111:11101110:11 mmreg1 mmreg2\n""00001111:11101110 mod mmreg r/m\n""00001111:11011110:11 mmreg1 mmreg2\n""00001111:11011110 mod mmreg r/m\n""00001111:11101010:11 mmreg1 mmreg2\n""00001111:11101010 mod mmreg r/m\n""00001111:11011010:11 mmreg1 mmreg2\n""00001111:11011010 mod mmreg r/m\n""00001111:11010111:11 mmreg1 r32\n""00001111:11100100:11 mmreg1 mmreg2\n""00001111:11100100 mod mmreg r/m\n""00001111:11110110:11 mmreg1 mmreg2\n""00001111:11110110 mod mmreg r/m\n""00001111:01110000:11 mmreg1 mmreg2: imm8\n""00001111:01110000:11 mod mmreg r/m: imm8\n""00001111:11110111:11 mmreg1 mmreg2\n""00001111:00101011 mod xmmreg r/m\n""00001111:11100111 mod mmreg r/m\n""00001111:00011000:01 mem\n""00001111:00011000:10 mem\n""00001111:00011000:11 mem\n""00001111:00011000:00 mem\n""00001111:10101110:11111000\n""11011 001 : 1111 0000\n""11011 001 : 1110 0001\n""11011 000 : mod 000 r/m\n""11011 100 : mod 000 r/m\n""11011 d00 : 11 000 ST(i)\n""11011 110 : 11 000 ST(i)\n""11011 111 : mod 100 r/m \n""11011 111 : mod 110 r/m\n""11011 001 : 1110 0000\n""11011 011 : 1110 0010\n""11011 010 : 11 000 ST(i)\n""11011 010 : 11 001 ST(i)\n""11011 010 : 11 010 ST(i)\n""11011 010 : 11 011 ST(i)\n""11011 011 : 11 000 ST(i)\n""11011 011 : 11 001 ST(i)\n""11011 011 : 11 010 ST(i)\n""11011 011 : 11 011 ST(i)\n""11011 000 : mod 010 r/m\n""11011 100 : mod 010 r/m\n""11011 000 : 11 010 ST(i)\n""11011 000 : mod 011 r/m\n""11011 100 : mod 011 r/m\n""11011 000 : 11 011 ST(i)\n""11011 110 : 11 011 001\n""11011 011 : 11 110 ST(i)\n""11011 111 : 11 110 ST(i)\n""11011 001 : 1111 1111\n""11011 001 : 1111 0110\n""11011 000 : mod 110 r/m\n""11011 100 : mod 110 r/m\n""11011 d00 : 1111 R ST(i)\n""11011 110 : 1111 1 ST(i)\n""11011 000 : mod 111 r/m\n""11011 100 : mod 111 r/m\n""11011 d00 : 1111 R ST(i)\n""1011 110 : 1111 0 ST(i)\n""11011 101 : 1100 0 ST(i)\n""11011 110 : mod 000 r/m\n""11011 010 : mod 000 r/m\n""11011 110 : mod 010 r/m\n""11011 010 : mod 010 r/m\n""11011 110 : mod 011 r/m\n""11011 010 : mod 011 r/m\n""11011 110 : mod 110 r/m\n""11011 010 : mod 110 r/m\n""11011 110 : mod 111 r/m\n""11011 010 : mod 111 r/m\n""11011 111 : mod 000 r/m\n""11011 011 : mod 000 r/m\n""11011 111 : mod 101 r/m\n""11011 110 : mod 001 r/m\n""11011 010 : mod 001 r/m\n""11011 001 : 1111 0111\n""11011 111 : mod 010 r/m\n""11011 011 : mod 010 r/m\n""11011 111 : mod 011 r/m\n""11011 011 : mod 011 r/m\n""11011 111 : mod 111 r/m\n""11011 110 : mod 100 r/m\n""11011 010 : mod 100 r/m\n""11011 110 : mod 101 r/m\n""11011 010 : mod 101 r/m\n""11011 001 : mod 000 r/m\n""11011 101 : mod 000 r/m\n""11011 011 : mod 101 r/m\n""11011 001 : 11 000 ST(i)\n""11011 001 : 1110 1000\n""11011 001 : mod 101 r/m\n""11011 001 : mod 100 r/m\n""11011 001 : 1110 1010\n""11011 001 : 1110 1001\n""11011 001 : 1110 1100\n""11011 001 : 1110 1101\n""11011 001 : 1110 1011\n""11011 001 : 1110 1110\n""11011 000 : mod 001 r/m\n""11011 100 : mod 001 r/m\n""11011 d00 : 1100 1 ST(i)\n""11011 110 : 1100 1 ST(i)\n""11011 001 : 1101 0000\n""11011 001 : 1111 0011\n""11011 001 : 1111 1000\n""11011 001 : 1111 0101\n""11011 001 : 1111 0010\n""11011 001 : 1111 1100\n""11011 101 : mod 100 r/m\n""11011 101 : mod 110 r/m\n""11011 001 : 1111 1101\n""11011 001 : 1111 1110\n""11011 001 : 1111 1011\n""11011 001 : 1111 1010\n""11011 001 : mod 010 r/m\n""11011 101 : mod 010 r/m\n""11011 101 : 11 010 ST(i)\n""11011 001 : mod 111 r/m\n""11011 001 : mod 110 r/m\n""11011 001 : mod 011 r/m\n""11011 101 : mod 011 r/m\n""11011 011 : mod 111 r/m\n""11011 101 : 11 011 ST(i)\n""11011 111 : 1110 0000\n""11011 101 : mod 111 r/m\n""11011 000 : mod 100 r/m\n""11011 100 : mod 100 r/m\n""11011 d00 : 1110 R ST(i)\n""11011 110 : 1110 1 ST(i)\n""11011 000 : mod 101 r/m\n""11011 100 : mod 101 r/m\n""11011 d00 : 1110 R ST(i)\n""11011 110 : 1110 0 ST(i)\n""11011 001 : 1110 0100\n""11011 101 : 1110 0 ST(i)\n""11011 101 : 1110 1 ST(i)\n""11011 010 : 1110 1001\n""11011 011 : 11 101 ST(i)\n""11011 111 : 11 101 ST(i)\n""11011 001 : 1110 0101\n""11011 001 : 1100 1 ST(i)\n""11011 001 : 1111 0100\n""11011 001 : 1111 0001\n""11011 001 : 1111 1001\n""1001 1011\n""####\n";


void *Memcpy(void *dst, const void *src, size_t count)
{
	void *ret = dst;
	while (count--)
	{
		*(char*)dst = *(char*)src;
		dst = (char*)dst + 1;
		src = (char*)src + 1;
	}
	return (ret);
}

//-------------------------------------------------------------------------

void *Memset(void *dst, int val, size_t count)
{
	void *start = dst;
	while (count--)
	{
		*(char*)dst = (char)val;
		dst = (char*)dst + 1;
	}

	return (start);
}

//-------------------------------------------------------------------------

char *Strstr(const char *str1, const char *str2)
{
	char *cp = (char*)str1;
	char *s1,  *s2;

	if (! *str2)
	{
		return ((char*)str1);
	}

	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;

		while (*s1 &&  *s2 && !(*s1 -  *s2))
		{
			s1++, s2++;
		}

		if (! *s2)
		{
			return (cp);
		}

		cp++;
	}

	return (nullptr);

}

//-------------------------------------------------------------------------

int Detour::IsHotpatchable(void *Target)
{
	return (*(long*)((char*)Target - 5) == 0x90909090L) && ((*(long*)((char*)Target - 1) &0x00ff8b90L) == 0x00ff8b90L);
}

//-------------------------------------------------------------------------

int Detour::IsHotpatched(void *Target)
{
	return (*((char*)Target - 5) == (char)0xe9U) && (*(short*)(Target) == (short)0xf9eb);
}

//-------------------------------------------------------------------------

int IsHotpatchedTo(void *Callback, void *Target)
{
	return (*((char*)Target - 5) == (char)0xe9U) && (*(short*)(Target) == (short)0xf9eb) && (*((signed long*)Target - 1) == (char*)Callback - (char*)Target);
}

//-------------------------------------------------------------------------

void *Detour::ApplyHotpatch(void *Callback, void *Target)
{
	void *ProtectAddress,  *Next;
	ULONG OldProtect, ProtectSize;
	ProtectAddress = Target;
	ProtectSize = 5;
	if (NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, PAGE_EXECUTE_READWRITE, &OldProtect) == 0)
	{
		if (Detour::IsHotpatchable(Target))
		{
			*(short*)Target = (short)0xf9eb;
			*((char*)Target - 5) = (char)0xe9U;
			*((signed long*)Target - 1) = (char*)Callback - (char*)Target;
			Next = (char*)Target + 2;
		}
		else
		{
			Next = 0;
		}
		NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, OldProtect, &OldProtect);
		return Next;
	}
	else
	{
		return 0;
	}
}

//-------------------------------------------------------------------------

int Detour::RemoveHotpatch(void *Target)
{
	void *ProtectAddress;
	ULONG OldProtect, ProtectSize;
	int r;
	ProtectAddress = Target;
	ProtectSize = 5;
	if (NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, PAGE_EXECUTE_READWRITE, &OldProtect) == 0)
	{
		if (Detour::IsHotpatched(Target))
		{
			*(long*)((char*)Target - 5) = 0x90909090L;
			*((char*)Target - 1) = (char)0x90;
			*(short*)Target = (short)0x00ff8b;
			r = 1;
		}
		else
		{
			r = 0;
		}
		NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, OldProtect, &OldProtect);
		return r;
	}
	else
	{
		return 0;
	}
}

//-------------------------------------------------------------------------

void __cdecl Detour::RemoveHotpatches(void *Target, ...)
{
	void **param;
	for (param = &Target;  *param; ++param)
	{
		Detour::RemoveHotpatch(*param);
	}
}

//-------------------------------------------------------------------------

void *Detour::CreateRedirectHeap(void)
{
	return RedirectHeap = RtlCreateHeap(HEAP_GROWABLE | HEAP_CREATE_ENABLE_EXECUTE | HEAP_NO_SERIALIZE, 0, 0, 0, 0, 0);
}

//-------------------------------------------------------------------------

void *Detour::DestroyRedirectHeap(void)
{
	return RtlDestroyHeap(RedirectHeap);
}

//-------------------------------------------------------------------------

int ParseInstruction(void *Address, PINSTRUCTION_INFO Info)
{
	unsigned char *p;
	char *pstart,  *pend,  *pt, strbuf[128], strbuf2[128], strpar[128];
	int OSize, ASize, Alt, Found, prefix, c, d, len, len2, w, s, r;
	p = (unsigned char*)Address;
	OSize = 0;
	ASize = 0;
	while (*p == 0xf0 ||  *p == 0xf2 ||  *p == 0xf3 ||  *p == 0x2e ||  *p == 0x36 ||  *p == 0x3e ||  *p == 0x26 ||  *p == 0x64 ||  *p == 0x65 ||  *p == 0x66 ||  *p == 0x67 ||  *p == 0xf)
	{
		if (!OSize)
		{
			OSize = (*p == 0x66);
		}
		if (!ASize)
		{
			ASize = (*p == 0x67);
		}
		++p;
	}
	prefix = p - (unsigned char*)Address;
	Alt = (*p == 0x0f);
	if (Info)
	{
		Info->Alt = Alt;
		Info->ASize = ASize;
		Info->OSize = OSize;
		if (Alt)
		{
			Info->Opcode = *(p + 1);
			Info->Operand = *(long*)(p + 2);
		}
		else
		{
			Info->Opcode =  *p;
			Info->Operand = *(long*)(p + 1);
		}
		Info->PrefixSize = prefix;
	}
	Memcpy(strpar, ToBin[p[0]], 8);
	Memcpy(strpar + 8, ToBin[p[1]], 8);
	Memcpy(strpar + 16, ToBin[p[2]], 8);
	Memcpy(strpar + 24, ToBin[p[3]], 8);
	strpar[32] = 0;
	pend = pstart = InstructionFormat;
	while (*pstart != '#')
	{
		while (*pend != 13 &&  *pend != 10)
		{
			++pend;
		}
		len = 0;
		for (c = 0; c < pend - pstart; ++c)
			if (pstart[c] != ' ')
			{
				strbuf[len++] = pstart[c];
			}
			strbuf[len] = 0;
			if (pt = Strstr(strbuf, "ST(i)"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = ' ';
			}
			if (pt = Strstr(strbuf, "r32"))
			{
				pt[0] = pt[1] = pt[2] = '?';
			}
			if (pt = Strstr(strbuf, "mmxreg1"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = pt[6] = ' ';
			}
			if (pt = Strstr(strbuf, "mmxreg2"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = pt[6] = ' ';
			}
			if (pt = Strstr(strbuf, "mmxreg"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = ' ';
			}
			if (pt = Strstr(strbuf, "xmmreg1"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = pt[6] = ' ';
			}
			if (pt = Strstr(strbuf, "xmmreg2"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = pt[6] = ' ';
			}
			if (pt = Strstr(strbuf, "xmmreg"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = ' ';
			}
			if (pt = Strstr(strbuf, "mmreg1"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = ' ';
			}
			if (pt = Strstr(strbuf, "mmreg2"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = pt[5] = ' ';
			}
			if (pt = Strstr(strbuf, "mmreg"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = ' ';
			}
			if (pt = Strstr(strbuf, "m32"))
			{
				pt[0] = pt[1] = pt[2] = pt[3] = pt[4] = pt[5] = '?';
				pt[6] = 0;
			}
			if (pt = Strstr(strbuf, "m512"))
			{
				pt[0] = pt[1] = pt[2] = pt[3] = pt[4] = pt[5] = '?';
				pt[6] = 0;
			}
			if (pt = Strstr(strbuf, "mem"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				if (pt[3] == 0)
				{
					pt[3] = pt[4] = pt[5] = '?';
					pt[6] = 0;
				}
			}
			if (pt = Strstr(strbuf, "sreg2"))
			{
				pt[0] = pt[1] = '?';
				pt[2] = pt[3] = pt[4] = ' ';
			}
			if (pt = Strstr(strbuf, "sreg3"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = pt[4] = ' ';
			}
			if (pt = Strstr(strbuf, "reg1"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = ' ';
			}
			if (pt = Strstr(strbuf, "reg2"))
			{
				pt[0] = pt[1] = pt[2] = '?';
				pt[3] = ' ';
			}
			if (pt = Strstr(strbuf, "reg"))
			{
				pt[0] = pt[1] = pt[2] = '?';
			}
			if (pt = Strstr(strbuf, "tttn"))
			{
				pt[0] = pt[1] = pt[2] = pt[3] = '?';
			}
			if (pt = Strstr(strbuf, "immediatedata"))
			{
				*(pt++) = 'X';
				Memset(pt, ' ', 12);
			}
			if (pt = Strstr(strbuf, "imm8data"))
			{
				*(pt++) = 'A';
				Memset(pt, ' ', 7);
			}
			if (pt = Strstr(strbuf, "imm8"))
			{
				*(pt++) = 'A';
				Memset(pt, ' ', 3);
			}
			if (pt = Strstr(strbuf, "fulldisplacement"))
			{
				*(pt++) = 'D';
				Memset(pt, ' ', 15);
			}
			if (pt = Strstr(strbuf, "unsignedfulloffset"))
			{
				*(pt++) = 'D';
				Memset(pt, ' ', 17);
			}
			if (pt = Strstr(strbuf, "selector"))
			{
				*(pt++) = 'B';
				Memset(pt, ' ', 7);
			}
			if (pt = Strstr(strbuf, "16-bitdisplacement"))
			{
				*(pt++) = 'B';
				Memset(pt, ' ', 17);
			}
			if (pt = Strstr(strbuf, "8-bitlevel(L)"))
			{
				*(pt++) = 'A';
				Memset(pt, ' ', 12);
			}
			if (pt = Strstr(strbuf, "8-bitdisplacement"))
			{
				*(pt++) = 'A';
				Memset(pt, ' ', 16);
			}
			if (pt = Strstr(strbuf, "type"))
			{
				*(pt++) = 'A';
				pt[0] = pt[1] = pt[2] = ' ';
			}
			if (pt = Strstr(strbuf, "portnumber"))
			{
				*(pt++) = 'B';
				Memset(pt, ' ', 9);
			}
			len2 = 0;
			for (c = 0; c < len; ++c)
				if (strbuf[c] != ' ')
				{
					strbuf2[len2++] = (strbuf[c] == 'g' || strbuf[c] == 'd' || strbuf[c] == 'R') ? '?' : strbuf[c];
				}
				strbuf2[len2] = 0;
				r = 1;
				d = 0;
				w = 2;
				s = 2;
				Found = 1;
				c = 0;
				do
				{
					if (strbuf2[c] == '?' || strbuf2[c] == ' ')
					{
						++d;
						++c;
						continue;
					}
					else if (strbuf2[c] == 's')
					{
						s = strpar[d] - '0';
					}
					else if (strbuf2[c] == 'w')
					{
						w = strpar[d] - '0';
					}
					else if (strbuf2[c] == ':')
					{
						++r;
						++c;
						if (strbuf2[c] == 'A')
							;
						else if (strbuf2[c] == 'B')
						{
							++r;
						}
						else if (strbuf2[c] == 'D')
						{
							r += 3;
						}
						else if (strbuf2[c] == 'X')
						{
							if (s != 1 && w)
							{
								if (OSize)
								{
									++r;
								}
								else
								{
									r += 3;
								}
							}
						}
						else if (strbuf2[c] == 'm' && strbuf2[c + 1] == 'o' && strbuf2[c + 2] == 'd')
						{
							if (ASize)
							{
								if (strpar[d] == '0' && strpar[d + 1] == '0')
								{
									if (strpar[d + 5] == '1' && strpar[d + 6] == '1' && strpar[d + 7] == '0')
									{
										r += 2;
									}
								}
								else if (strpar[d] == '0' && strpar[d + 1] == '1')
								{
									++r;
								}
								else if (strpar[d] == '1' && strpar[d + 1] == '0')
								{
									r += 2;
								}
							}
							else
							{
								if (strpar[d] == '0' && strpar[d + 1] == '0')
								{
									if (strpar[d + 5] == '1' && strpar[d + 6] == '0' && strpar[d + 7] == '1')
									{
										r += 4;
									}
									else if (strpar[d + 5] == '1' && strpar[d + 6] == '0' && strpar[d + 7] == '0')
									{
										++r;
									}
								}
								else if (strpar[d] == '0' && strpar[d + 1] == '1')
								{
									if (strpar[d + 5] == '1' && strpar[d + 6] == '0' && strpar[d + 7] == '0')
									{
										++r;
									}
									++r;
								}
								else if (strpar[d] == '1' && strpar[d + 1] == '0')
								{
									if (strpar[d + 5] == '1' && strpar[d + 6] == '0' && strpar[d + 7] == '0')
									{
										++r;
									}
									r += 4;
								}
							}
							c += 3;
							d += 2;
							continue;
						}
						if (strbuf2[c] == '0' || strbuf2[c] == '1')
						{
							if (strbuf2[c] != strpar[d])
							{
								Found = 0;
								break;
							}
						}
						++c;
						++d;
						continue;
					}
					else if (strbuf2[c] == '0' || strbuf2[c] == '1')
					{
						if (strbuf2[c] != strpar[d])
						{
							Found = 0;
							break;
						}
					}
					++c;
					++d;
				}
				while (c < len2);
				if (Found)
				{
					if (Info)
					{
						Info->Size = prefix + r;
					}
					return prefix + r;
				}
				while (*pend == 13 ||  *pend == 10)
				{
					++pend;
				}
				pstart = pend;
	}
	if (Info)
	{
		Info->Size = 1;
	}
	return 1;
}

//-------------------------------------------------------------------------

void *Detour::RedirectProcedure(void *Callback, void *Target)
{
	void *CodeBase,  *ProtectAddress,  *Next;
	char *p,  *np;
	ULONG ProtectSize;
	int i, j, disp, PrologSize, OriginalPrologSize, SizeDiff[8], InnerBranch[8];
	RELADDR_TYPE AddrType[8];
	INSTRUCTION_INFO Instructions[8];
	ULONG OldProtect;
	ProtectAddress = Target;
	ProtectSize = 5;
	if (Next = Detour::ApplyHotpatch(Callback, Target))
	{
		return Next;
	}
	if (!RedirectHeap)
		if (!CreateRedirectHeap())
		{
			return 0;
		}
		if (NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, PAGE_EXECUTE_READWRITE, &OldProtect) == 0)
		{
			PrologSize = 0, i =  - 1;
			do
			{
				PrologSize += ParseInstruction((void*)((size_t)Target + PrologSize), &Instructions[++i]);
			}
			while (PrologSize < 5);
			OriginalPrologSize = PrologSize;
			Instructions[i + 1].Size = 0;
			for (p = (char*)Target, i = 0; Instructions[i].Size; p += Instructions[i++].Size)
			{
				AddrType[i] = AbsAddr;
				SizeDiff[i] = 0;
				if (!Instructions[i].Alt)
				{
					if (Instructions[i].Opcode == 0xe9 || Instructions[i].Opcode == 0xe8)
					{
						if (Instructions[i].OSize)
						{
							if (!(InnerBranch[i] = InBound(p + Instructions[i].Size + (signed short)Instructions[i].Operand, Target, (char*)Target + OriginalPrologSize)))
							{
								PrologSize += (SizeDiff[i] = 5-Instructions[i].Size);
							}
							AddrType[i] = Instructions[i].Opcode == 0xe9 ? Jmp16 : Call16;
						}
						else
						{
							InnerBranch[i] = InBound(p + Instructions[i].Size + (signed long)Instructions[i].Operand, Target, (char*)Target + OriginalPrologSize);
							AddrType[i] = Instructions[i].Opcode == 0xe9 ? Jmp32 : Call32;
						}
					}
					else if (Instructions[i].Opcode == 0xeb)
					{
						AddrType[i] = Jmp8;
						if (!(InnerBranch[i] = InBound(p + Instructions[i].Size + (signed char)Instructions[i].Operand, Target, (char*)Target + OriginalPrologSize)))
						{
							PrologSize += (SizeDiff[i] = 5-Instructions[i].Size);
						}
					}
					else if (Instructions[i].Opcode == 0xe3)
					{
						AddrType[i] = Jcxz;
						if (!(InnerBranch[i] = InBound(p + Instructions[i].Size + (signed char)Instructions[i].Operand, Target, (char*)Target + OriginalPrologSize)))
						{
							PrologSize += (SizeDiff[i] = 7);
						}
					}
					else if ((Instructions[i].Opcode &0xF0) == 0x70)
					{
						AddrType[i] = Jcc8;
						if (!(InnerBranch[i] = InBound(p + Instructions[i].Size + (signed char)Instructions[i].Operand, Target, (char*)Target + OriginalPrologSize)))
						{
							PrologSize += (SizeDiff[i] = 6-Instructions[i].Size);
						}
					}
				}
				else if ((Instructions[i].Opcode &0xF0) == 0x80)
				{
					if (Instructions[i].OSize)
					{
						AddrType[i] = Jcc16;
						if (!(InnerBranch[i] = InBound(p + Instructions[i].Size + (signed char)Instructions[i].Operand, Target, (char*)Target + OriginalPrologSize)))
						{
							PrologSize += (SizeDiff[i] = 6-Instructions[i].Size);
						}
					}
					else
					{
						InnerBranch[i] = InBound(p + Instructions[i].Size + (signed long)Instructions[i].Operand, Target, (char*)Target + OriginalPrologSize);
						AddrType[i] = Jcc32;
					}
				}

			}
			CodeBase = RtlAllocateHeap(RedirectHeap, 0, 18+PrologSize);
			if (CodeBase)
			{
				*(long*)CodeBase = PrologSize;
				*((long*)CodeBase + 1) = OriginalPrologSize;
				Next = (void*)((size_t)CodeBase + 8);
				for (i = OriginalPrologSize - 1; i >= 0; --i)
				{
					((char*)Next)[i] = ((char*)Target)[i];
				}
				*((char*)Next + PrologSize + 5) = *(char*)Target;
				*(long*)((char*)Next + PrologSize + 6) = *(long*)((char*)Target + 1);
				for (p = (char*)Target, np = (char*)Next, i = 0; Instructions[i].Size; p += Instructions[i].Size, np += Instructions[i].Size, ++i)
				{

					if (AddrType[i] == AbsAddr)
					{
						Memcpy(np, p, Instructions[i].Size);
					}
					else
					{
						if (InnerBranch[i])
						{
							Memcpy(np, p, Instructions[i].Size);
						}
						if (AddrType[i] == Call32 || AddrType[i] == Jmp32)
						{
							if (InnerBranch[i] && Instructions[i].Operand && Instructions[i].Operand !=  - Instructions[i].Size)
							{
								for (disp = 0, j = i; (j >= 0) && (disp <= Abs(Instructions[j].Operand)) && (Instructions[j].Size); Instructions[i].Operand > 0 ? (disp += Instructions[++j].Size, *(signed long*)(np + Instructions[i].PrefixSize + 1) += SizeDiff[j]): (disp += Instructions[j].Size, *(signed long*)(np + Instructions[i].PrefixSize + 1) -= SizeDiff[j--]))
									;
							}
							else
							{
								Memcpy(np, p, Instructions[i].Size);
								*(long*)(np + Instructions[i].PrefixSize + 1) += (p - np);
							}
						}
						else if (AddrType[i] == Call16 || AddrType[i] == Jmp16)
						{
							if (InnerBranch[i] && (signed short)Instructions[i].Operand && (signed short)Instructions[i].Operand !=  - Instructions[i].Size)
							{
								for (disp = 0, j = i; (j >= 0) && (disp <= Abs(Instructions[j].Operand)) && (Instructions[j].Size); Instructions[i].Operand > 0 ? (disp += Instructions[++j].Size, *(signed short*)(np + Instructions[i].PrefixSize + 1) += SizeDiff[j]): (disp += Instructions[j].Size, *(signed short*)(np + Instructions[i].PrefixSize + 1) -= SizeDiff[j--]))
									;
							}
							else
							{
								*np = AddrType[i] == Call16 ? (char)0xe8: (char)0xe9;
								*(long*)(np + 1) = (signed short)Instructions[i].Operand + p - np - SizeDiff[i];
								np += SizeDiff[i];
								if (SizeDiff[i] < 0)
								{
									Memset(np, 0x90,  - SizeDiff[i]);
								}
							}
						}
						else if (AddrType[i] == Jmp8)
						{
							if (InnerBranch[i] && (signed char)Instructions[i].Operand && (signed char)Instructions[i].Operand !=  - Instructions[i].Size)
							{
								for (disp = 0, j = i; (j >= 0) && (disp <= Abs(Instructions[j].Operand)) && (Instructions[j].Size); Instructions[i].Operand > 0 ? (disp += Instructions[++j].Size, *(signed char*)(np + Instructions[i].PrefixSize + 1) += SizeDiff[j]): (disp += Instructions[j].Size, *(signed char*)(np + Instructions[i].PrefixSize + 1) -= SizeDiff[j--]))
									;
							}
							else
							{
								*np = AddrType[i] = (RELADDR_TYPE)0xe9;
								*(long*)(np + 1) = (signed char)Instructions[i].Operand + p - np - SizeDiff[i];
								np += SizeDiff[i];
								if (SizeDiff[i] < 0)
								{
									Memset(np, 0x90,  - SizeDiff[i]);
								}
							}
						}
						else if (AddrType[i] == Jcc32)
						{
							if (InnerBranch[i] && (signed long)Instructions[i].Operand && (signed long)Instructions[i].Operand !=  - Instructions[i].Size)
							{
								for (disp = 0, j = i; (j >= 0) && (disp <= Abs(Instructions[j].Operand)) && (Instructions[j].Size); Instructions[i].Operand > 0 ? (disp += Instructions[++j].Size, *(signed long*)(np + Instructions[i].PrefixSize + 2) += SizeDiff[j]): (disp += Instructions[j].Size, *(signed long*)(np + Instructions[i].PrefixSize + 2) -= SizeDiff[j--]))
									;
							}
							else
							{
								Memcpy(np, p, Instructions[i].Size);
								*(long*)(np + Instructions[i].PrefixSize + 2) += p - np;
							}
						}
						else if (AddrType[i] == Jcc16)
						{
							if (InnerBranch[i] && (signed short)Instructions[i].Operand && (signed short)Instructions[i].Operand !=  - Instructions[i].Size)
							{
								for (disp = 0, j = i; (j >= 0) && (disp <= Abs(Instructions[j].Operand)) && (Instructions[j].Size); Instructions[i].Operand > 0 ? (disp += Instructions[++j].Size, *(signed short*)(np + Instructions[i].PrefixSize + 2) += SizeDiff[j]): (disp += Instructions[j].Size, *(signed short*)(np + Instructions[i].PrefixSize + 2) -= SizeDiff[j--]))
									;
							}
							else
							{
								*(short*)np = *(short*)(p + Instructions[i].PrefixSize);
								*(long*)(np + 2) = (signed short)Instructions[i].Operand + p - np - SizeDiff[i];
								np += SizeDiff[i];
								if (SizeDiff[i] < 0)
								{
									Memset(np, 0x90,  - SizeDiff[i]);
								}
							}
						}
						else if (AddrType[i] == Jcc8)
						{
							if (InnerBranch[i] && (signed char)Instructions[i].Operand && (signed char)Instructions[i].Operand !=  - Instructions[i].Size)
							{
								for (disp = 0, j = i; (j >= 0) && (disp <= Abs(Instructions[j].Operand)) && (Instructions[j].Size); Instructions[i].Operand > 0 ? (disp += Instructions[++j].Size, *(signed char*)(np + Instructions[i].PrefixSize + 1) += SizeDiff[j]): (disp += Instructions[j].Size, *(signed char*)(np + Instructions[i].PrefixSize + 1) -= SizeDiff[j--]))
									;
							}
							else
							{
								*(short*)np = *(short*)(p + Instructions[i].PrefixSize);
								*(long*)(np + 2) = (signed char)Instructions[i].Operand + p - np - SizeDiff[i];
								np += SizeDiff[i];
								if (SizeDiff[i] < 0)
								{
									Memset(np, 0x90,  - SizeDiff[i]);
								}
							}
						}
						else if (AddrType[i] == Jcxz)
						{
							if (InnerBranch[i] && (signed char)Instructions[i].Operand && (signed char)Instructions[i].Operand !=  - Instructions[i].Size)
							{
								for (disp = 0, j = i; (j >= 0) && (disp <= Abs(Instructions[j].Operand)) && (Instructions[j].Size); Instructions[i].Operand > 0 ? (disp += Instructions[++j].Size, *(signed char*)(np + Instructions[i].PrefixSize + 1) += SizeDiff[j]): (disp += Instructions[j].Size, *(signed char*)(np + Instructions[i].PrefixSize + 1) -= SizeDiff[j--]))
									;
							}
							else
							{
								Memcpy(np, p, Instructions[i].Size);
								*(unsigned long*)(np + Instructions[i].PrefixSize + 1) = 0xe905eb02;
								*(unsigned long*)(np + Instructions[i].PrefixSize + 5) = (signed char)Instructions[i].Operand + p - np - SizeDiff[i];
								np += SizeDiff[i];
							}
						}
					}
				}
				*(char*)((size_t)Next + PrologSize) = (char)0xe9;
				*(signed long*)((size_t)Next + PrologSize + 1) = (size_t)Target + OriginalPrologSize - (size_t)Next - PrologSize - 5;
				*(char*)Target = (char)0xe9U;
				*(signed long*)((size_t)Target + 1) = (size_t)Callback - (size_t)Target - 5;
				NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, OldProtect, &OldProtect);
			}
			else
			{
				Next = 0;
			}
			return Next;
		}
		return 0;
}

//-------------------------------------------------------------------------

int IsRedirectedTo(void *Callback, void *Target)
{
	return IsHotpatchedTo(Callback, Target) || ((*(char*)Target == (char)0xe9U) && ((char*)Callback == (char*)Target + *(signed long*)((char*)Target + 1) + 5));
}

//-------------------------------------------------------------------------

void __cdecl RedirectProcedures(void *Callback, void *, void **, ...)
{
	void * * * param;
	for (param = (void * **) &Callback; param[0] && param[1] && param[2]; param += 3)
	{
		if (IsRedirectedTo(param[0], param[1]))
		{
			continue;
		}
		*(param[2]) = Detour::RedirectProcedure(param[0], param[1]);
	}
}

//-------------------------------------------------------------------------

void *Detour::RestoreProcedure(void *Next)
{
	void *CodeBase,  *Target,  *ProtectAddress;
	ULONG ProtectSize, OldProtect;
	int PrologSize, OriginalPrologSize;
	if (Next)
	{
		if (Target = (char*)Next - 2, Detour::RemoveHotpatch(Target))
		{
			return Target;
		}
		CodeBase = (void*)((size_t)Next - 8);
		PrologSize = *(long*)CodeBase;
		OriginalPrologSize = *((long*)CodeBase + 1);
		Target = (void*)(*(long*)((size_t)Next + PrologSize + 1) + (size_t)Next + PrologSize + 5-OriginalPrologSize);
		ProtectAddress = Target;
		ProtectSize = 5;
		if (NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, PAGE_EXECUTE_READWRITE, &OldProtect) == 0)
		{
			*(char*)Target = *((char*)Next + PrologSize + 5);
			*(long*)((size_t)Target + 1) = *(long*)((size_t)Next + PrologSize + 6);
			RtlFreeHeap(RedirectHeap, 0, CodeBase);
			NtProtectVirtualMemory(AppBase::GetCurrentProcess(), &ProtectAddress, &ProtectSize, OldProtect, &OldProtect);
		}
		else
		{
			Target = 0;
		}
		return Target;
	}
	else
	{
		return 0;
	}
}

//-------------------------------------------------------------------------

void __cdecl Detour::RestoreProcedures(void *Next, ...)
{
	void **param;
	for (param = &Next;  *param; ++param)
	{
		Detour::RestoreProcedure(*param);
	}
}

//-------------------------------------------------------------------------


static int ValidateHeaders(HANDLE FileHandle, PIMAGE_DOS_HEADER DosHeader, PIMAGE_NT_HEADERS NtHeaders)
{
	LARGE_INTEGER ByteOffset = 
	{
		0, 0
	};
	IO_STATUS_BLOCK iosb;
	if (NtReadFile(FileHandle, 0, 0, 0, &iosb, DosHeader, sizeof(IMAGE_DOS_HEADER), &ByteOffset, 0) >= 0)
	{
		if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
		{
			return 0;
		}
		ByteOffset.LowPart = DosHeader->e_lfanew;
		if (NtReadFile(FileHandle, 0, 0, 0, &iosb, NtHeaders, sizeof(IMAGE_NT_HEADERS), &ByteOffset, 0) >= 0)
		{
			if (NtHeaders->Signature != IMAGE_NT_SIGNATURE && NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
			{
				return 0;
			}
			else
			{
				return 1;
			}
		}
	}
	return 0;
}

//-------------------------------------------------------------------------

static DWORD GetFileOffset(HANDLE FileHandle, DWORD RVA, PIMAGE_DOS_HEADER DosHeader, PIMAGE_NT_HEADERS NtHeaders)
{
	if (DosHeader || ValidateHeaders(FileHandle, DosHeader, NtHeaders))
	{
		LARGE_INTEGER ByteOffset;
		IMAGE_SECTION_HEADER SectionHeader;
		WORD c = NtHeaders->FileHeader.NumberOfSections;
		ByteOffset.LowPart = DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS);
		ByteOffset.HighPart = 0;
		while (c-- && ByteOffset.LowPart < NtHeaders->OptionalHeader.SizeOfHeaders - DosHeader->e_lfanew)
		{
			IO_STATUS_BLOCK iosb;
			if (NtReadFile(FileHandle, 0, 0, 0, &iosb, &SectionHeader, sizeof(IMAGE_SECTION_HEADER), &ByteOffset, 0) >= 0)
			{
				if (RVA >= SectionHeader.VirtualAddress && RVA < SectionHeader.VirtualAddress + SectionHeader.SizeOfRawData)
				{
					return RVA - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
				}
			}
			else
			{
				break;
			}
			ByteOffset.LowPart += sizeof(IMAGE_SECTION_HEADER);
		}
	}
	return 0;
}

//-------------------------------------------------------------------------

DWORD GetExportedRVA(HANDLE FileHandle, char *Name, unsigned NameLength)
{
	LARGE_INTEGER ByteOffset = 
	{
		0, 0
	};
	IO_STATUS_BLOCK iosb;
	IMAGE_DOS_HEADER DosHeader;
	IMAGE_NT_HEADERS NtHeaders;
	if (ValidateHeaders(FileHandle, &DosHeader, &NtHeaders))
	{
		DWORD ExpRVA = NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
		DWORD ExpSize = NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
		if (ExpRVA && ExpSize)
		{
			IMAGE_EXPORT_DIRECTORY ExpDir;
			ByteOffset.LowPart = GetFileOffset(FileHandle, ExpRVA, &DosHeader, &NtHeaders);
			if (NtReadFile(FileHandle, 0, 0, 0, &iosb, &ExpDir, sizeof(IMAGE_EXPORT_DIRECTORY), &ByteOffset, 0) >= 0)
			{
				unsigned i;
				LARGE_INTEGER OffsetOfNameRVA = 
				{
					GetFileOffset(FileHandle, ExpDir.AddressOfNames, &DosHeader, &NtHeaders), 0
				};
				char *ExpName = (char*)_malloca(NameLength + 1);
				for (i = 0; i < ExpDir.NumberOfNames; ++i, OffsetOfNameRVA.LowPart += 4)
				{
					DWORD NameRVA;
					if (NtReadFile(FileHandle, 0, 0, 0, &iosb, &NameRVA, sizeof(NameRVA), &OffsetOfNameRVA, 0) >= 0)
					{
						LARGE_INTEGER OffsetOfName = 
						{
							GetFileOffset(FileHandle, NameRVA, &DosHeader, &NtHeaders), 0
						};
						if (NtReadFile(FileHandle, 0, 0, 0, &iosb, ExpName, NameLength, &OffsetOfName, 0) >= 0)
						{
							if (memcmp(Name, ExpName, NameLength) == 0 && ExpName[NameLength] == 0)
							{
								WORD Ordinal;
								DWORD OrdinalRVA = ExpDir.AddressOfNameOrdinals + i * sizeof(WORD);
								LARGE_INTEGER OffsetOfOrdinal = 
								{
									GetFileOffset(FileHandle, OrdinalRVA, &DosHeader, &NtHeaders), 0
								};
								if (NtReadFile(FileHandle, 0, 0, 0, &iosb, &Ordinal, sizeof(WORD), &OffsetOfOrdinal, 0) >= 0)
								{
									DWORD RVA;
									DWORD RVARVA = ExpDir.AddressOfFunctions + Ordinal * sizeof(DWORD);
									LARGE_INTEGER OffsetOfRVA = 
									{
										GetFileOffset(FileHandle, RVARVA, &DosHeader, &NtHeaders), 0
									};
									if (NtReadFile(FileHandle, 0, 0, 0, &iosb, &RVA, sizeof(DWORD), &OffsetOfRVA, 0) >= 0)
									{
										return RVA;
									}
								}
							}
						}
					}
				}

			}
		}
	}
	return 0;
}

//-------------------------------------------------------------------------

static HMODULE LastImageBase = 0;
static HANDLE LastFileHandle = 0;
long Detour::CloseLastFileHandle(void)
{
	return NtClose(LastFileHandle);
}

//-------------------------------------------------------------------------

long Detour::SetTargetModule(wchar_t *ModuleName, unsigned NameLength)
{
	UNICODE_STRING FileName;
	long Result;
	FileName.Buffer = ModuleName;
	FileName.Length = FileName.MaximumLength = NameLength;
	Result = LdrGetDllHandle(0, 0, &FileName, (PVOID *)&LastImageBase);
	if (Result == 0)
	{
		struct
		{
			UNICODE_STRING Name;
			wchar_t buf[256];
		} buf;
		ULONG ReturnLength;
		if (NtQueryVirtualMemory(AppBase::GetCurrentProcess(), LastImageBase, MemoryMappedFilenameInformation, &buf, sizeof buf, &ReturnLength) == 0)
		{
			IO_STATUS_BLOCK iosb;
			OBJECT_ATTRIBUTES oa = makeoa(&buf.Name);
			if (NtCreateFile(&LastFileHandle, FILE_READ_DATA | SYNCHRONIZE, &oa, &iosb, 0, 0, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 0, 0) < 0)
			{
				LastFileHandle = 0;
			}
		}
	}
	return Result;
}

//-------------------------------------------------------------------------

__declspec(noinline)void *Detour::RedirectProcedureByName(void *Callback, char *Name, unsigned NameLength)
{
	ANSI_STRING name;
	void *Target;
	if (LastFileHandle)
	{
		DWORD RVA = GetExportedRVA(LastFileHandle, Name, NameLength);
		if (RVA)
		{
			return RedirectProcedure(Callback, (void*)(RVA + (size_t)LastImageBase));
		}
	}
	name.Buffer = Name;
	name.Length = name.MaximumLength = NameLength;
	if (LdrGetProcedureAddress(LastImageBase, &name, 0, &Target) == 0)
	{
		return Detour::RedirectProcedure(Callback, Target);
	}
	else
	{
		return 0;
	}
}

